package com.it.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.it.reggie.dto.DishDto;
import com.it.reggie.entity.Dish;
import com.it.reggie.entity.DishFlavor;
import com.it.reggie.mapper.DishMapper;
import com.it.reggie.service.DishFlavorService;
import com.it.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
//当使用@Autowired注解时，如果出现项目无法启动的问题，可能是由于：
    //1.存在循环依赖，即A依赖于B，而B又依赖于A，会导致无法完成依赖注入，从而导致项目无法启动。

    //@Autowired//会报错，为什么，依赖循环，这个实现类已经实现了DishService，不能再注入DishService了
    //private DishService dishService;
//  想要调用dishService.方法()  ,可以这样写：this.方法()   ,可见，this就是代指本类的implements后面的DishService
    @Autowired
    private DishFlavorService dishFlavorService;//DishFlavorService用来操作口味表（DishFlavorService extends IService<DishFlavor>）

    //新增菜品同时保存对应的口味数据
    @Override//响应backend-page-food-add.html里的462行的方法的ajax请求
    @Transactional//(因为涉及到多张表)要加入事务控制，需要在启动类开启@EnableTransactionManagement，开启事务注解支持
    public void saveWithFlavor(DishDto dishDto) {//标记事务边界，在使用数据库进行操作时，确保要么全部成功提交，要么全部回滚
        //保存菜品（基本信息）到菜品表dish  /一·操作dish表
        this.save(dishDto);//DishDto继承了Dish，扩展了菜品对应的口味数据List<DishFlavor> flavors = 。。作为属性
//DishFlavor只是封装了name 和 value,dishId没有封装上(是空的)，为什么？？？？？ 因为name和value是从前端的修改项目页面上提交回来的,
// 就不知道设置的这个口味是哪个菜品的口味，所以在保存之前。。。填充上id值
        Long dishId = dishDto.getId();//表dish的id就是表dish_flavor的dish_id
//获取dishDto里继承的dish里的菜品id，给从dishDto获取到的每一个DishFlavor属性对象(此DishFlavor只是封装了name和value，其它的属性(如dishId)为空)添加一个id值
//??????????????????????????????????????????????????????????????????????
        //菜品口味//菜品口味数据flavors在DishDto里有(封装了，封装成一个对象)，get方法在@data里
        List<DishFlavor> flavors = dishDto.getFlavors();
//对集合flavors进行处理，遍历flavors，把集合里的每个元素DishFlavor(对象)遍历出来，然后为每个DishFlavor的属性dishId赋上上一句从继承了Dish的DishDto里get到的dishId值
        //处理(dishDto.getFlavors())这个集合
        //flavors.forEach();或者：
        flavors = flavors.stream().map((item) -> {//遍历出来的每一项都叫item
        //处理完再赋给他自己
            item.setDishId(dishId);
            return item;
        }).collect(Collectors.toList());//加工(给每一个DishFlavor的dishId赋好值)之后，重新转成list集合
        //保存菜品口味数据到菜品口味表dish_flavor，其实要保存的就是dishDto里的List<DishFlavor> flavors集合
        dishFlavorService.saveBatch(flavors);//集合批量保存  /二·操作口味表
    }

    //根据id查询菜品信息以及他所对应的口味信息
    @Override
    public DishDto getByIdWithFlavor(Long id) {
        //查询菜品基本信息，从dish表查
        Dish dish = this.getById(id);//根据传来的id查一个dish对象(包含基本信息)
        DishDto dishDto = new DishDto();
        //                        源 ，
        BeanUtils.copyProperties(dish,dishDto);//普通的属性都拷进dishDto了,后面再给dishDto的其他属性单独赋值

        //查询当前菜品对应的口味信息，从dish_flavor表查询
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();//条件构造器
        queryWrapper.eq(DishFlavor::getDishId,dish.getId());//根据菜品dishId查对应的口味，dish.getId()可以直接用id（当前传过来的参数）代替
        //把DishFlavor的dishId和dish的id匹配的DishFlavor查出来
        List<DishFlavor> flavors = dishFlavorService.list(queryWrapper);//单独查询了口味的集合
//检索与条件匹配的“DishFlavor”对象列表从“dishFlavorService”调用方法list(),结果列表存储在'list'变量中。
        //赋给他(dishDto:要返回的对象)刚刚查上来的值
        dishDto.setFlavors(flavors);//给dishDto填充需要用到的属性的值

        //需要返回的1是DishDto对象
        return dishDto;

    }

    @Override//事务注解，保证数据的一致性//需要在启动类开启@EnableTransactionManagement
    @Transactional//标记事务边界，在使用数据库进行操作时，确保要么全部成功提交，要么全部回滚
    public void updateWithFlavor(DishDto dishDto) {
        //更新dish表基本信息,dishService可以用this代表？？？？？？？
        //dishFlavorService.updateById(dishDto);//报错
        this.updateById(dishDto);//?????this代表dishService么，代表dishFlavorService???

        //清理当前菜品对应口味数据---dish_flavor表的delete操作,delete from dish_flavor where dish_id = ???
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(DishFlavor::getDishId,dishDto.getId());//dishId在dishDto里(直接写作id)可以找到,在DishFlavor里写作dishId
//delete from dish_flavor where dish_id = ???
        dishFlavorService.remove(queryWrapper);

        //添加当前新提交过来的口味数据---dish_flavor表的insert操作
        List<DishFlavor> flavors = dishDto.getFlavors();//口味数据在dishDto里封装了，get出来
//DishFlavor只封装了name和value，没有dishId，为什么？？？？？ 因为name和value是从前端的修改菜品页面上提交回来的,
//(而前端的name和value是通过上面的getByIdWithFlavor(Long id)方法查询匹配得到的，写到页面上就只需要/剩name和value，不需要/丢失了dishId)
        flavors = flavors.stream().map((item) -> {//给每个DishFlavor的属性dishId填充完值之后再赋回给他自己
//遍历当前的List<DishFlavor>,把每一个DishFlavor拿出来，给每一个DishFlavor都set一个dishId
            item.setDishId(dishDto.getId());//dishId要用此方法的参数get到
            return item;
        }).collect(Collectors.toList());//加工(给每一个DishFlavor的dishId赋好值)之后，重新转成list集合
        dishFlavorService.saveBatch(flavors);//批量保存，()里填的是要保存的数据的对象的集合或数组
    }
}
